#include <graphics/material.h>
#include <ticpp/ticpp.h>
#include <render/texture2d.h>
#include <graphics/image2d.h>

namespace yam3d
{
namespace graphics
{

RenderState::RenderState()
    : core::Object(__FUNCTION__)
    ,  m_cullMode(CULL_BACK)
    , m_depthEnable(true)
{
}

RenderState::~RenderState()
{
}

void RenderState::setCullMode(RenderState::CullMode cullMode)
{
    m_cullMode = cullMode;
}

void RenderState::setDepthEnable(bool depthEnable)
{
    m_depthEnable = depthEnable;
}

RenderState::CullMode RenderState::getCullMode()const
{
    return m_cullMode;
}

bool RenderState::isDepthEnabled() const
{
    return m_depthEnable;
}

SamplerState::SamplerState()
    : core::Object(__FUNCTION__)
    , m_wrapS(REPEAT)
    , m_wrapT(REPEAT)
    , m_wrapR(REPEAT)
    , m_minifyFilter(NEAREST)
    , m_magnifyFilter(NEAREST)
{
}

SamplerState::~SamplerState()
{
}

void SamplerState::setWrapping(Wrapping wrapS, Wrapping wrapT, Wrapping wrapR)
{
    m_wrapS = wrapS;
    m_wrapT = wrapT;
    m_wrapR = wrapR;
}

void SamplerState::setFiltering( Filtering minifyFilter, Filtering magnifyFilter )
{
    assert( magnifyFilter == NEAREST || magnifyFilter == LINEAR );
    m_minifyFilter = minifyFilter;
    m_magnifyFilter = magnifyFilter;
}

SamplerState::Wrapping SamplerState::getWrappingS() const
{
    return m_wrapS;
}

SamplerState::Wrapping SamplerState::getWrappingT() const
{
    return m_wrapT;
}

SamplerState::Wrapping SamplerState::getWrappingR() const
{
    return m_wrapR;
}

SamplerState::Filtering SamplerState::getMinifyFilter() const
{
    return m_minifyFilter;
}

SamplerState::Filtering SamplerState::getMagnifyFilter() const
{
    return m_magnifyFilter;
}

Pass::Pass()
    : core::Object(__FUNCTION__)
    , m_renderState()
    , m_samplerStages()
    , m_shader(0)
    , m_shaderUniforms(0)
    , m_cameraRef("")
    //, m_cameraTransform()
   // , m_cameraProjection()
    //, m_camera(0)
{
    //m_cameraProjection.setToIdentity();
   // m_cameraTransform.setToIdentity();
}

Pass::~Pass()
{
}

/*void Pass::setCamera( const math::mat4& cameraTransform, const math::mat4& cameraProjection )
{
    m_cameraProjection = cameraProjection;
    m_cameraTransform = cameraTransform;
   // m_camera = camera;
}*/

void Pass::setShaderUniforms( graphics::ShaderUniforms* shaderUniforms)
{
    m_shaderUniforms = shaderUniforms;
}

void Pass::setShaderProgram( render::ShaderProgram* shaderProgram )
{
    m_shader = shaderProgram;
}

void Pass::setTexture(int index, const core::string& name, render::Texture* texture)
{
    if( index <= getSamplerCount() )
    {
        m_samplerStages.resize(index+1);
    }
    assert(0 <= index && index < m_samplerStages.size());

    m_samplerStages[index].name = name;
    m_samplerStages[index].texture = texture;

    if( m_samplerStages[index].samplerState == 0 )
    {
        m_samplerStages[index].samplerState = new SamplerState();
    }
}

void Pass::setRenderState(RenderState* renderState)
{
    m_renderState = renderState;
}

void Pass::setSamplerState(int index, SamplerState* samplerState)
{
    assert(0 <= index && index < m_samplerStages.size());
    m_samplerStages[index].samplerState = samplerState;
}
/*
RenderState& Pass::getRenderState()
{
    return m_renderState;
}

SamplerState& Pass::getSamplerState(int index)
{
    assert(0 <= index && index < m_samplerStages.size());
    return m_samplerStages[index].samplerState;
}
*/
RenderState* Pass::getRenderState()
{
    return m_renderState;
}

SamplerState* Pass::getSamplerState(int index)
{
    assert(0 <= index && index < m_samplerStages.size());
    return m_samplerStages[index].samplerState;
}

/*graphics::Camera* Pass::getCamera() const
{
    return m_camera;
}*/

graphics::ShaderUniforms* Pass::getShaderUniforms() const
{
    return m_shaderUniforms.ptr();
}

render::ShaderProgram* Pass::getShaderProgram() const
{
    return m_shader.ptr();
}

int Pass::getSamplerCount() const
{
    return m_samplerStages.size();
}

const RenderState* Pass::getRenderState() const
{
    return m_renderState.ptr();
}

const SamplerState* Pass::getSamplerState(int index) const
{
    assert(0 <= index && index < m_samplerStages.size());
    return m_samplerStages[index].samplerState.ptr();
}

render::Texture* Pass::getTexture(int index) const
{
    assert(0 <= index && index < m_samplerStages.size());
    return m_samplerStages[index].texture.ptr();
}

const core::string& Pass::getSamplerName(int index) const
{
    assert(0 <= index && index < m_samplerStages.size());
    return m_samplerStages[index].name;
}


Effect::Effect()
: core::Object(__FUNCTION__)
{
}

Effect::~Effect()
{
}

void Effect::setPass(int index, Pass* pass)
{
    if( index <= getPassCount() )
    {
        m_passes.resize(index+1);
    }

    assert(0 <= index && index < m_passes.size());

    m_passes[index] = pass;
}

int Effect::getPassCount() const
{
    return m_passes.size();
}

Pass* Effect::getPass(int index) const
{
    assert(0 <= index && index < m_passes.size());
    assert( m_passes[index] != 0 );
    return m_passes[index].ptr();
}

/*
void printRec(ticpp::Element* e1, int recLevel)
{
    for( ticpp::Element* e=e1->FirstChildElement(false); e != 0; e=e->NextSiblingElement(false) )
    {
        core::string t;
        for(int i=0; i<recLevel; ++i )
        {
            t += "  ";
        }
        qDebug("%s<%s>\n", t.toStdString().c_str(), e->Value().c_str() );
        printRec( e, recLevel+1 );
        qDebug("%s</%s>\n", t.toStdString().c_str(), e->Value().c_str() );
    }
}*/


namespace Internal
{
    bool convertBool( const core::string& value )
    {
        if( value == "TRUE")
        {
            return true;
        }
        else if( value == "FALSE" )
        {
            return false;
        }
        else
        {
            assert( 0 ); // Unsupported DepthEnable value
        }
    }

    struct Shader : public core::Object
    {
        Shader()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~Shader()
        {
        }

        core::string name;
        core::string shaderType;
        core::string fileName;
        core::Ref<render::Shader> shader;
    };

    void parse(Shader* shader, ticpp::Element* shaderElement )
    {
        shader->name = shaderElement->GetAttribute("NAME").c_str();
        shader->shaderType = shaderElement->GetAttribute("SHADER_TYPE").c_str();
        shader->fileName = shaderElement->GetAttribute("FILE_NAME").c_str();
        shader->shader = 0;
        assert( shader->shaderType == "FRAGMENT" || shader->shaderType == "VERTEX" );
    }

    struct ShaderProgram : public core::Object
    {
        ShaderProgram()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~ShaderProgram()
        {
        }

        core::string name;
        core::vector< core::Ref<Shader> > shaders;
        core::Ref<render::ShaderProgram> shaderProgram;
    };

    void parse(ShaderProgram* shaderProgram, ticpp::Element* shaderProgramElement )
    {
        shaderProgram->name = shaderProgramElement->GetAttribute("NAME").c_str();
        shaderProgram->shaderProgram = 0;

        for( ticpp::Element* e=shaderProgramElement->FirstChildElement(); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "Shader" )
            {
                Shader* shader = new Shader();
                parse(shader,e);
                shaderProgram->shaders.append(shader);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
    }

    struct State
    {
        core::string name;
        core::string value;
    };

    void parse(State* state, ticpp::Element* stateElement )
    {
        state->name = stateElement->GetAttribute("NAME").c_str();
        state->value = stateElement->GetAttribute("VALUE").c_str();
    }

    struct SamplerState : public core::Object
    {
        SamplerState()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~SamplerState()
        {
        }

        core::string name;
        core::vector<State> states;
        core::Ref<graphics::SamplerState> samplerState;
    };

    void parse(SamplerState* samplerState, ticpp::Element* samplerStateElement )
    {
        samplerState->name = samplerStateElement->GetAttribute("NAME").c_str();
        samplerState->samplerState = 0;

        for( ticpp::Element* e=samplerStateElement->FirstChildElement(); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "State" )
            {
                State state;
                parse(&state,e);
                samplerState->states.append(state);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
    }

    struct RenderState : public core::Object
    {
        RenderState()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~RenderState()
        {
        }

        core::string name;
        core::vector<State> states;
        core::Ref<graphics::RenderState> renderState;
    };

    void parse(RenderState* renderState, ticpp::Element* renderStateElement )
    {
        renderState->name = renderStateElement->GetAttribute("NAME").c_str();
        renderState->renderState = 0;

        for( ticpp::Element* e=renderStateElement->FirstChildElement(); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "State" )
            {
                State state;
                parse(&state,e);
                renderState->states.append(state);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
    }

    struct Texture : public core::Object
    {
        Texture()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~Texture()
        {
        }

        core::string name;
        core::string fileName;
        core::Ref<graphics::Image2D> image;
        core::Ref<render::Texture2D> texture;
    };

    void parse(Texture* texture, ticpp::Element* textureElement )
    {
        texture->name = textureElement->GetAttribute("NAME").c_str();
        texture->fileName = textureElement->GetAttribute("FILE_NAME").c_str();
        texture->image = 0;
        texture->texture = 0;
    }

    struct Vector3Variable
    {
        core::string name;
        core::string variableSemantic;
        math::vec3 value;
    };

    void parse(Vector3Variable* vector3Variable, ticpp::Element* vector3VariableElement )
    {
        vector3Variable->name = vector3VariableElement->GetAttribute("NAME").c_str();
        vector3Variable->variableSemantic = vector3VariableElement->GetAttribute("VARIABLE_SEMANTIC").c_str();
        vector3Variable->value.setX( vector3VariableElement->GetAttribute<float>("VALUE_X") );
        vector3Variable->value.setY( vector3VariableElement->GetAttribute<float>("VALUE_Y") );
        vector3Variable->value.setZ( vector3VariableElement->GetAttribute<float>("VALUE_Z") );
    }

    struct FloatVariable
    {
        core::string name;
        core::string variableSemantic;
        float value;
    };

    void parse(FloatVariable* floatVariable, ticpp::Element* floatVariableElement )
    {
        floatVariable->name = floatVariableElement->GetAttribute("NAME").c_str();
        floatVariable->variableSemantic = floatVariableElement->GetAttribute("VARIABLE_SEMANTIC").c_str();
        floatVariable->value = floatVariableElement->GetAttribute<float>("VALUE");
    }

    struct BoolVariable
    {
        core::string name;
        core::string variableSemantic;
        bool value;
    };

    void parse(BoolVariable* boolVariable, ticpp::Element* boolVariableElement )
    {
        boolVariable->name = boolVariableElement->GetAttribute("NAME").c_str();
        boolVariable->variableSemantic = boolVariableElement->GetAttribute("VARIABLE_SEMANTIC").c_str();
        boolVariable->value = convertBool( boolVariableElement->GetAttribute("VALUE").c_str() );
    }

    struct ShaderUniforms : public core::Object
    {
        ShaderUniforms()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~ShaderUniforms()
        {
        }

        core::string name;
        core::vector<Vector3Variable> vec3Variables;
        core::vector<FloatVariable> floatVariables;
        core::vector<BoolVariable> boolVariables;
        core::Ref<graphics::ShaderUniforms> shaderUniforms;
    };

    void parse(ShaderUniforms* shaderUniforms, ticpp::Element* shaderUniformsElement )
    {
        shaderUniforms->shaderUniforms = 0;
        shaderUniforms->name = shaderUniformsElement->GetAttribute("NAME").c_str();
        for( ticpp::Element* e=shaderUniformsElement->FirstChildElement(false); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "Vector3Variable" )
            {
                Vector3Variable vector3Variable;
                parse(&vector3Variable,e);
                shaderUniforms->vec3Variables.append(vector3Variable);
            }
            else if ( e->Value() == "FloatVariable" )
            {
                FloatVariable floatVariable;
                parse(&floatVariable,e);
                shaderUniforms->floatVariables.append(floatVariable);
            }
            else if ( e->Value() == "BoolVariable" )
            {
                BoolVariable boolVariable;
                parse(&boolVariable,e);
                shaderUniforms->boolVariables.append(boolVariable);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }

   //     vector3Variable->variableSemantic = vector3VariableElement->GetAttribute("VARIABLE_SEMANTIC").c_str();
   //     vector3Variable->value.setX( vector3VariableElement->GetAttribute<float>("VALUE_X") );
   //     vector3Variable->value.setY( vector3VariableElement->GetAttribute<float>("VALUE_Y") );
   //     vector3Variable->value.setZ( vector3VariableElement->GetAttribute<float>("VALUE_Z") );
    }

    struct Sampler
    {
        int index;
        core::string name;
        core::string textureRef;
        core::string samplerRef;
    };

    void parse(Sampler* sampler, ticpp::Element* samplerElement )
    {
        sampler->index = samplerElement->GetAttribute<int>("INDEX");
        sampler->name = samplerElement->GetAttribute("NAME").c_str();
        sampler->textureRef = samplerElement->GetAttribute("TEXTURE_REF").c_str();
        sampler->samplerRef = samplerElement->GetAttribute("SAMPLER_STATE_REF").c_str();
    }

    struct Pass : public core::Object
    {
        Pass()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~Pass()
        {
        }

        core::string name;
        int passIndex;
        core::string cameraRef;
        core::string renderStateRef;
        core::string shaderProgramRef;
        core::string shaderUniformsRef;
        core::vector<Sampler> samplers;
        core::Ref<graphics::Pass> pass;
    };

    void parse(Pass* pass, ticpp::Element* passElement )
    {        
        pass->name = passElement->GetAttribute("NAME").c_str();
        pass->passIndex = passElement->GetAttribute<int>("PASS_INDEX");
        pass->cameraRef = passElement->GetAttribute("CAMERA_REF").c_str();
        pass->renderStateRef = passElement->GetAttribute("RENDER_STATE_REF").c_str();
        pass->shaderProgramRef = passElement->GetAttribute("SHADER_PROGRAM_REF").c_str();
        pass->shaderUniformsRef = passElement->GetAttribute("SHADER_UNIFORMS_REF").c_str();
        pass->pass = 0;

        for( ticpp::Element* e=passElement->FirstChildElement(false); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "Sampler" )
            {
                Sampler sampler;
                parse(&sampler,e);
                pass->samplers.append(sampler);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
    }

    struct Effect : public core::Object
    {
        Effect()
            : core::Object(__FUNCTION__)
        {
        }

        virtual ~Effect()
        {
        }

         core::string name;
         core::vector< core::Ref<Pass> > passes;
         core::Ref<graphics::Effect> effect;
    };

    void parse(Effect* effect, ticpp::Element* effectElement )
    {
        effect->name = effectElement->GetAttribute("NAME").c_str();
        effect->effect = 0;

        for( ticpp::Element* e=effectElement->FirstChildElement(); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "Pass" )
            {
                Pass* pass = new Pass();
                parse(pass,e);
                effect->passes.append(pass);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
     //   qDebug("Effect: \"%s\" parsed", effect->name.toStdString().c_str() );
    }



    //using namespace Internal;
    struct EffectGroup : public core::Object
    {
        EffectGroup()
        : core::Object(__FUNCTION__)
        {}

        virtual ~EffectGroup()
        {
        }

         core::vector< core::Ref<Internal::ShaderProgram> > shaderPrograms;
         core::vector< core::Ref<Internal::SamplerState> > samplerStates;
         core::vector< core::Ref<Internal::RenderState> > renderStates;
         core::vector< core::Ref<Internal::ShaderUniforms> > shaderUniforms;
         core::vector< core::Ref<Internal::Texture> > textures;
         core::vector< core::Ref<Internal::Effect> > effects;

    };

    void parse(EffectGroup* effectGroup, ticpp::Element* effectGroupElement )
    {
        for( ticpp::Element* e=effectGroupElement->FirstChildElement(); e!=0; e=e->NextSiblingElement(false) )
        {
            if( e->Value() == "ShaderProgram" )
            {
                Internal::ShaderProgram* shaderProgram = new Internal::ShaderProgram();
                parse(shaderProgram,e);
                effectGroup->shaderPrograms.append(shaderProgram);
            }
            else if( e->Value() == "SamplerState" )
            {
                Internal::SamplerState* samplerState = new Internal::SamplerState();
                parse(samplerState,e);
                effectGroup->samplerStates.append(samplerState);
            }
            else if( e->Value() == "RenderState" )
            {
                Internal::RenderState* renderState = new Internal::RenderState();
                parse(renderState,e);
                effectGroup->renderStates.append(renderState);
            }
            else if( e->Value() == "Texture" )
            {
                Internal::Texture* texture = new Internal::Texture();
                parse(texture,e);
                effectGroup->textures.append(texture);
            }
            else if( e->Value() == "ShaderUniforms" )
            {
                Internal::ShaderUniforms* shaderUniforms = new Internal::ShaderUniforms();
                parse(shaderUniforms,e);
                effectGroup->shaderUniforms.append(shaderUniforms);
            }
            else if( e->Value() == "Effect" )
            {
                Internal::Effect* effect = new Internal::Effect();
                parse(effect,e);
                effectGroup->effects.append(effect);
            }
            else
            {
                assert(0); // Invelid element found
            }
        }
    }

    graphics::RenderState::CullMode convertCulling( const core::string& value )
    {
        if( value == "CULL_BACK")
        {
            return graphics::RenderState::CULL_BACK;
        }
        else if( value == "CULL_FRONT" )
        {
            return graphics::RenderState::CULL_FRONT;
        }
        else if( value == "CULL_NONE" )
        {
            return graphics::RenderState::CULL_NONE;
        }
        else
        {
            assert( 0 ); // Unsupported CullMode value
        }
    }

    graphics::SamplerState::Wrapping convertWrapping( const core::string& value )
    {
        if( value == "REPEAT")
        {
            return graphics::SamplerState::REPEAT;
        }
        else if( value == "CLAMP" )
        {
            return graphics::SamplerState::CLAMP;
        }
        else
        {
            assert( 0 ); // Unsupported Wrapping value
        }
    }

    graphics::SamplerState::Filtering convertFiltering( const core::string& value )
    {
        if( value == "NEAREST")
        {
            return graphics::SamplerState::NEAREST;
        }
        else if( value == "LINEAR" )
        {
            return graphics::SamplerState::LINEAR;
        }
        else if( value == "NEAREST_MIPMAP_NEAREST" )
        {
            return graphics::SamplerState::NEAREST_MIPMAP_NEAREST;
        }
        else if( value == "NEAREST_MIPMAP_LINEAR" )
        {
            return graphics::SamplerState::NEAREST_MIPMAP_LINEAR;
        }
        else if( value == "LINEAR_MIPMAP_NEAREST" )
        {
            return graphics::SamplerState::LINEAR_MIPMAP_NEAREST;
        }
        else if( value == "LINEAR_MIPMAP_LINEAR" )
        {
            return graphics::SamplerState::LINEAR_MIPMAP_LINEAR;
        }
        else
        {
            assert( 0 ); // Unsupported Filtering value
        }
    }


}


EffectFile::EffectFile( const core::string& fileName)
    : core::Object(__FUNCTION__)
   , effectGroup(new Internal::EffectGroup)
{
    qDebug("Loading effect file: %s", fileName.toStdString().c_str());
    ticpp::Document doc( fileName.toStdString() );
    doc.LoadFile();
    ticpp::Element* e=doc.FirstChildElement("EffectGroup",false);

    parse(effectGroup,e);
}

EffectFile::~EffectFile()
{
}

int EffectFile::getEffectCount() const
{
    return effectGroup->effects.size();
}

Effect* EffectFile::getEffect(int index )
{
    assert( 0 <= index && index<getEffectCount() );

    Internal::Effect* e = effectGroup->effects[index];
    if( e->effect == 0 )
    {
        create(e);
    }

    assert( e != 0 );
    return e->effect;
}

Effect* EffectFile::getEffect(const core::string& name)
{
    for( int i=0; i<effectGroup->effects.size(); ++i )
    {
        if( effectGroup->effects[i]->name == name )
        {
            Internal::Effect* e = effectGroup->effects[i];
            if( e->effect == 0 )
            {
                create(e);
            }

            assert( e != 0 );
            return e->effect;
        }
    }

    return 0;
}

void EffectFile::create(Internal::Effect* effect)
{
    effect->effect = new graphics::Effect();
    for( int i=0; i<effect->passes.size(); ++i )
    {
        Internal::Pass* pass = effect->passes[i];
        if( pass->pass == 0 )
        {
            create(pass);
        }
        assert( pass->pass != 0 );

        effect->effect->setPass( pass->passIndex, pass->pass );
    }
}

void EffectFile::create(Internal::Pass* pass)
{
    pass->pass = new graphics::Pass();
    pass->pass->setCameraRef( pass->cameraRef );
    pass->pass->setRenderState( getRenderStateRef(pass->renderStateRef) );
    pass->pass->setShaderProgram( getShaderProgramRef(pass->shaderProgramRef) );
    pass->pass->setShaderUniforms( getShaderUniformsRef(pass->shaderUniformsRef) );

    for( int i=0; i<pass->samplers.size(); ++i )
    {
        Internal::Sampler* sampler = &pass->samplers[i];
        pass->pass->setTexture( sampler->index, sampler->name, getTextureRef(sampler->textureRef) );
        pass->pass->setSamplerState(sampler->index, getSamplerStateRef(sampler->samplerRef) );
    }
}

void EffectFile::create(Internal::Shader* shader)
{
    qDebug( "Creating shader \"%s\" ", shader->name.toStdString().c_str() );
    if( shader->shaderType == "FRAGMENT" )
    {
        shader->shader = new render::Shader(QGLShader::Fragment);
    }
    else if( shader->shaderType == "VERTEX" )
    {
        shader->shader = new render::Shader(QGLShader::Vertex);
    }
    else
    {
         assert(0); // Invalid shader type
    }

    if( !shader->shader->compileSourceFile(shader->fileName) )
    {
        assert(0); // failed to compile source file
    }
}

void EffectFile::create(Internal::ShaderProgram* shaderProgram)
{
    qDebug( "Creating shader program \"%s\" ", shaderProgram->name.toStdString().c_str() );
    shaderProgram->shaderProgram = new render::ShaderProgram();
    for( int i=0; i<shaderProgram->shaders.size(); ++i )
    {
        if( shaderProgram->shaders[i]->shader == 0 )
        {
            create(shaderProgram->shaders[i]);
        }

        shaderProgram->shaderProgram->addShader( shaderProgram->shaders[i]->shader );

    }

    if( !shaderProgram->shaderProgram->link() || !shaderProgram->shaderProgram->isLinked() )
    {
        assert( 0 ); // failed to link shader
    }

    shaderProgram->shaderProgram->bind();
}

void EffectFile::create(Internal::RenderState* renderState)
{
    renderState->renderState = new graphics::RenderState();

    for( int i=0; i<renderState->states.size(); ++i )
    {
        core::string name = renderState->states[i].name;
        core::string value = renderState->states[i].value;
        if( name == "CullMode")
        {
            renderState->renderState->setCullMode( Internal::convertCulling(value) );
        }
        else if( name == "DepthEnable" )
        {
            renderState->renderState->setDepthEnable( Internal::convertBool(value) );
        }
        else
        {
            assert( 0 ); // Unsupported render state option
        }
    }
}


void EffectFile::create(Internal::SamplerState* samplerState)
{
    samplerState->samplerState = new graphics::SamplerState();

    for( int i=0; i<samplerState->states.size(); ++i )
    {
        core::string name = samplerState->states[i].name;
        core::string value = samplerState->states[i].value;
        if( name == "WrapS")
        {
            samplerState->samplerState->setWrapping(
                    Internal::convertWrapping(value),
                    samplerState->samplerState->getWrappingT(),
                    samplerState->samplerState->getWrappingR() );
        }
        else if( name == "WrapT" )
        {
            samplerState->samplerState->setWrapping(
                    samplerState->samplerState->getWrappingS(),
                    Internal::convertWrapping(value),
                    samplerState->samplerState->getWrappingR() );
        }
        else if( name == "WrapR" )
        {
            samplerState->samplerState->setWrapping(
                    samplerState->samplerState->getWrappingS(),
                    samplerState->samplerState->getWrappingT(),
                    Internal::convertWrapping(value) );
        }
        else if( name == "MinifyFilter" )
        {
            samplerState->samplerState->setFiltering(
                    Internal::convertFiltering(value),
                    samplerState->samplerState->getMagnifyFilter());
        }
        else if( name == "MagnifyFilter" )
        {
            samplerState->samplerState->setFiltering(
                    samplerState->samplerState->getMinifyFilter(),
                    Internal::convertFiltering(value));
        }
        else
        {
            assert( 0 ); // Unsupported render state option
        }
    }
}

namespace Internal
{
    template <class T>
    void setUniformArrays(graphics::ShaderUniforms* shaderUniforms, const core::vector<T>& array )
    {
        for( int i=0; i<array.size(); ++i )
        {
            if( array[i].variableSemantic.length() == 0 )
            {
                shaderUniforms->setUniformValue(array[i].name.toStdString().c_str(), array[i].value );
            }
            else
            {
                shaderUniforms->setUniformSemanticValue( array[i].name.toStdString().c_str(), array[i].value, array[i].variableSemantic.toStdString().c_str() );
            }
        }
    }
}

void EffectFile::create(Internal::ShaderUniforms* shaderUniforms)
{
    shaderUniforms->shaderUniforms = new graphics::ShaderUniforms();

    setUniformArrays(shaderUniforms->shaderUniforms,shaderUniforms->vec3Variables);
    setUniformArrays(shaderUniforms->shaderUniforms,shaderUniforms->floatVariables);
    setUniformArrays(shaderUniforms->shaderUniforms,shaderUniforms->boolVariables);
}

/*
graphics::Camera* EffectFile::getCameraRef(const core::string& refName)
{
    assert(m_mainCamera!=0);
    return m_mainCamera;
}*/

graphics::RenderState* EffectFile::getRenderStateRef(const core::string& refName)
{
    for( int i=0; i<effectGroup->renderStates.size(); ++i )
    {
        Internal::RenderState* renderState = effectGroup->renderStates[i];
        if( renderState->name == refName )
        {
            if( renderState->renderState == 0 )
            {
                create(renderState);
            }
            assert(renderState->renderState != 0);
            return renderState->renderState;
        }
    }

    return 0;
}

render::ShaderProgram* EffectFile::getShaderProgramRef(const core::string& refName)
{
    for( int i=0; i<effectGroup->shaderPrograms.size(); ++i )
    {
        Internal::ShaderProgram* shaderProgram = effectGroup->shaderPrograms[i];
        if( shaderProgram->name == refName )
        {
            if( shaderProgram->shaderProgram == 0 )
            {
                create(shaderProgram);
            }
            assert(shaderProgram->shaderProgram != 0);
            return shaderProgram->shaderProgram;
        }
    }

    return 0;
}

render::Texture2D* EffectFile::getTextureRef(const core::string& refName)
{
    for( int i=0; i<effectGroup->textures.size(); ++i )
    {
        Internal::Texture* texture = effectGroup->textures[i];
        if( texture->name == refName )
        {
            if( texture->texture == 0 )
            {
                qDebug( "Creating texture \"%s\" from the file: \"%s\" ", texture->name.toStdString().c_str(), texture->fileName.toStdString().c_str() );
                if( texture->image == 0 )
                {
                    texture->image = new Image2D(texture->fileName.toStdString().c_str());
                }

                texture->texture = new render::Texture2D(texture->image);
            }
            assert(texture->texture != 0);
            return texture->texture;
        }
    }

    return 0;
}

graphics::SamplerState* EffectFile::getSamplerStateRef(const core::string& refName)
{
    for( int i=0; i<effectGroup->samplerStates.size(); ++i )
    {
        Internal::SamplerState* samplerState = effectGroup->samplerStates[i];
        if( samplerState->name == refName )
        {
            if( samplerState->samplerState == 0 )
            {
                create(samplerState);
            }
            assert(samplerState->samplerState != 0);
            return samplerState->samplerState;
        }
    }

    return 0;
}

graphics::ShaderUniforms* EffectFile::getShaderUniformsRef(const core::string& refName)
{
    for( int i=0; i<effectGroup->shaderUniforms.size(); ++i )
    {
        Internal::ShaderUniforms* shaderUniforms = effectGroup->shaderUniforms[i];
        if( shaderUniforms->name == refName )
        {
            if( shaderUniforms->shaderUniforms == 0 )
            {
                create(shaderUniforms);
            }
            assert(shaderUniforms->shaderUniforms != 0);
            return shaderUniforms->shaderUniforms;
        }
    }

    return 0;
}

}
}
